package org.jadapter.spring;

import java.util.Map;

import org.jadapter.servicelookup.ServiceLookup;
import org.jadapter.servicelookup.ServiceLookupDelegate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * A Spring implementation of ServiceLookupDelegate, which looks up
 * services as beans in the application context.
 * 
 * To configure this in Spring, do:
 * 
 * <pre>
 * &lt;beans&gt;
 * 
 * 	&lt;bean id="serviceLookupDelegate" class="org.jadapter.spring.SpringBeanServiceLookupDelegate" /&gtl
 * 
 *  <!-- other beans here -->
 * 
 * &lt;/beans&gt;
 * </pre>
 * 
 * It is generally advisable for this to be among the first beans configured.
 * 
 * @author optilude
 * @since 0.4
 *
 */
public class SpringBeanServiceLookupDelegate implements ServiceLookupDelegate, ApplicationContextAware, InitializingBean {
	
	private ApplicationContext applicationContext;
	
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	
	/**
	 * When spring finishes setting up this bean, wire up the service
	 * lookup static.
	 */
	public void afterPropertiesSet() throws Exception {
		if(ServiceLookup._getServiceLookupDelegate() != null) {
			throw new RuntimeException("Service lookup delegate already set!");
		}
		ServiceLookup._setServiceLookupDelegate(this);
	}
	
	// Implementation of ServiceLookupDelegate
	
	public <T> T lookupService(Class<T> type) {
		Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, type);
        if(beans.isEmpty()) {
            return null;
        }
        return (T)beans.values().iterator().next();
	}

	public <T> T lookupService(Class<T> type, String name) {
		Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, type);
        if(beans.isEmpty()) {
            return null;
        }
        return (T)beans.get(name);
	}

}
